package org.jianfa.mq.seckill.service.impl;

import org.jianfa.mq.seckill.entity.po.OrderInfo;
import org.jianfa.mq.seckill.entity.po.SeckillOrder;
import org.jianfa.mq.seckill.entity.vo.GoodsVo;
import org.jianfa.mq.seckill.mapper.OrderInfoMapper;
import org.jianfa.mq.seckill.mapper.SeckillOrderMapper;
import org.jianfa.mq.seckill.redis.GoodsKeyPrefix;
import org.jianfa.mq.seckill.redis.OrderKeyPrefix;
import org.jianfa.mq.seckill.redis.RedisService;
import org.jianfa.mq.seckill.service.OrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

@Service
public class OrderServiceImpl implements OrderService {

    private final static Logger logger = LoggerFactory.getLogger(org.jianfa.mq.seckill.service.OrderService.class);

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private SeckillOrderMapper seckillOrderMapper;

    @Autowired
    private RedisService redisService;

    /**
     * 通过用户id与商品id从订单列表中获取订单信息，这个地方用到了唯一索引（unique index!!!!!）
     * <p>
     * c5: 优化，不同每次都去数据库中读取秒杀订单信息，而是在第一次生成秒杀订单成功后，
     * 将订单存储在redis中，再次读取订单信息的时候就直接从redis中读取
     *
     * @param userId
     * @param goodsId
     * @return 秒杀订单信息
     */
    public SeckillOrder getSeckillOrderByUserIdAndGoodsId(Long userId, long goodsId) {

        // 从redis中取缓存，减少数据库的访问
        SeckillOrder seckillOrder = redisService.get(OrderKeyPrefix.getSeckillOrderByUidGid, ":" + userId + "_" + goodsId, SeckillOrder.class);
        if (seckillOrder != null) {
            return seckillOrder;
        }

        return seckillOrderMapper.findByUserIdAndGoodsId(userId, goodsId);
//        return seckillOrder;
    }


    /**
     * 获取订单信息
     *
     * @param orderId
     * @return
     */
    public OrderInfo getOrderById(long orderId) {
        return orderInfoMapper.selectByPrimaryKey(orderId);
    }

    /**
     * 创建订单
     * <p>
     * c5: 增加redis缓存
     *
     * @param userId
     * @param goods
     * @return
     */
    @Transactional
    public OrderInfo createOrder(long userId, GoodsVo goods) {
        OrderInfo orderInfo = new OrderInfo();
        SeckillOrder seckillOrder = new SeckillOrder();

        orderInfo.setCreateDate(new Date());
        orderInfo.setDeliveryAddrId(0L);
        orderInfo.setGoodsCount(1);// 订单中商品的数量
        orderInfo.setGoodsId(goods.getId());
        orderInfo.setGoodsName(goods.getGoodsName());
        orderInfo.setGoodsPrice(goods.getSeckillPrice());// 秒杀价格
        orderInfo.setOrderChannel(1);
        orderInfo.setStatus(0);
        orderInfo.setUserId(userId);

        // 将订单信息插入order_info表中
        long orderId = orderInfoMapper.insert(orderInfo);

        seckillOrder.setGoodsId(goods.getId());
        seckillOrder.setOrderId(orderInfo.getId());
        seckillOrder.setUserId(userId);
        // 将秒杀订单插入miaosha_order表中
        seckillOrderMapper.insert(seckillOrder);

        // 将秒杀订单信息存储于redis中
        redisService.set(OrderKeyPrefix.getSeckillOrderByUidGid, ":" + userId + "_" + goods.getId(), seckillOrder);

        logger.info("生成订单。orderId:{}", orderId);

        return orderInfo;
    }

    @Transactional
    public void checkOrder(OrderInfo oldOrderInfo) {
        Long id = oldOrderInfo.getId();
        Long goodsId = oldOrderInfo.getGoodsId();

        OrderInfo newOrderInfo = orderInfoMapper.selectByPrimaryKey(id);
        Integer status = newOrderInfo.getStatus();
        if (0 == status) {
            newOrderInfo.setStatus(5); //已完成

            int updateRows = orderInfoMapper.updateByPrimaryKey(newOrderInfo);

            Long decr = redisService.decr(GoodsKeyPrefix.seckillGoodsStockPrefix, "" + goodsId);
            logger.info("检查到未支付的订单。取消该订单。id:{} goodsId:{} updateRows:{} decr:{}", id, goodsId, updateRows, decr);
        } else {
            logger.info("检查到已支付的订单。id:{} goodsId:{} status:{}", id, goodsId, status);
        }
    }
}
